home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Collection of Tools & Utilities
/
Collection of Tools and Utilities.iso
/
asmutil
/
bluebook.zip
/
FLOATPT.ASM
< prev
next >
Wrap
Assembly Source File
|
1986-05-14
|
23KB
|
843 lines
COMMENT ~
FLOATPT.ASM -- Floating Point Conversion Procedures
From `BLUEBOOK of ASSEMBLY ROUTINES for the IBM PC & XT'
by Christopher L. Morgan
Copyright (C) 1984 by The Waite Group, Inc.
Purpose:
Contents:
---------
BIN802DEC -- Convert from 80-bit binary to decimal digits
DECDOUBLE -- Double a temporary decimal floating point number
DECHALF -- Halve a temporary decimal floating point number
DECNORM -- Normalize temporary decimal floating point
DFP2SFP -- Convert from double to single precision floating point
FIX -- Convert from floating point to 16-bit integer
FLOAT -- Convert from 16-bit integer to floating point
FPIN -- Convert from external to internal floating point
FPINDIGIT -- Input single decimal digit to floating point
FPOUT -- Convert from internal to external floating point
FPTDIV -- Divide temporary floating point by 10
FPTMUL -- Multiply temporary floating point by 10
FPTNORM -- Normalize temporary floating point
SFP2DFP -- Convert from single to double precision floating point
SFP2TFP -- Convert from single precision to temporary floating point
SGNDEC16IN -- Convert from ASCII signed decimal to binary
TDECSHOW -- Display floating point
TFP2SFP -- Convert from temporary floating point to single precision
_____________________________________________________________________________
~
CODES SEGMENT
EXTRN STDIN:FAR,STDOUT:FAR
PUBLIC SGNDEC16IN,TFP2SFP,FPINDIGIT,FPTNORM,FPTMUL,FPTDIV,FPIN
PUBLIC SFP2TFP,TDECSHOW,BIN802DEC,DECNORM,DECHALF,DECDOUBLE,FPOUT
PUBLIC FIX,FLOAT,SFP2DFP,DFP2SFP,MBINADD,MBINSUB,MBINMUL,MBINDIV
ASSUME CS:CODES,DS:DATAS
;Equates
SIBYTE EQU BYTE PTR [SI]
SIWORD EQU WORD PTR [SI]
DIBYTE EQU BYTE PTR [DI]
DIWORD EQU WORD PTR [DI]
SFPBUFFW0 EQU WORD PTR SFPBUFF+0
SFPBUFFB2 EQU BYTE PTR SFPBUFF+2
SFPBUFFB3 EQU BYTE PTR SFPBUFF+3
SFPBUFFW2 EQU WORD PTR SFPBUFF+2
DFPBUFFW0 EQU WORD PTR DFPBUFF+0
DFPBUFFW2 EQU WORD PTR DFPBUFF+2
DFPBUFFW4 EQU WORD PTR DFPBUFF+4
DFPBUFFW6 EQU WORD PTR DFPBUFF+6
FPTEMP1W0 EQU WORD PTR FPTEMP1+0
FPTEMP1W2 EQU WORD PTR FPTEMP1+2
FPTEMP1W4 EQU WORD PTR FPTEMP1+4
FPTEMP1W6 EQU WORD PTR FPTEMP1+6
FPTEMP1W8 EQU WORD PTR FPTEMP1+8
FPTEMP1B10 EQU BYTE PTR FPTEMP1+10
FPTEMP1W11 EQU WORD PTR FPTEMP1+11
FPTEMP2W0 EQU WORD PTR FPTEMP2+0
FPTEMP2W2 EQU WORD PTR FPTEMP2+2
FPTEMP2W4 EQU WORD PTR FPTEMP2+4
FPTEMP2W6 EQU WORD PTR FPTEMP2+6
FPTEMP2W8 EQU WORD PTR FPTEMP2+8
FPTEMP2B10 EQU BYTE PTR FPTEMP2+10
FPTEMP2W11 EQU WORD PTR FPTEMP2+11
;__________________________ FLOATING POINT ROUTINES __________________________
;-----------------------------------------------------------------------------
;Convert from 80-bit binary to decimal digits
BIN802DEC PROC NEAR
;
;Clear the string
PUSH DI ;Save destination pointer
MOV AL,0 ;Zero byte
MOV CX,25 ; for a count of 25
BIN802DEC1:
MOV [DI],AL ;Zero the byte
INC DI ;Point to next byte
LOOP BIN802DEC1 ; until done
POP DI ;Restore destination pointer
;
;Keep looping
BIN802DEC2:
PUSH SI ;Save source pointer
;
;Divide mantissa by 10
MOV BX,0 ;Done flag
MOV CX,5 ;5 words in number
MOV DX,0 ;Previous remainder
ADD SI,8 ;Point to high end
BIN802DEC3:
PUSH CX ;Save count
MOV AX,[SI] ;Get 16-bit digit
MOV CX,10 ;Divisor of 10
DIV CX ;Divide
MOV [SI],AX ;Put 16-bit digit back
OR BX,AX ;Check for zero
SUB SI,2 ;Point to next 16-bit digit
POP CX ;Restore count
LOOP BIN802DEC3
MOV [DI],DL ;Remainder is decimal digit
INC DI ;Point to next decimal digit
POP SI ;Restore source pointer
CMP BX,0 ;Was the binary zero ?
JNZ BIN802DEC2 ; if so, loop
RET ; else return
BIN802DEC ENDP
;-----------------------------------------------------------------------------
;Double a temporary decimal floating point number
DECDOUBLE PROC NEAR
MOV CX,25 ;For a count of 25
MOV AH,0 ;Clear previous carry
DECDOUBLE1:
MOV AL,[DI] ;Get digit
SAL AL,1 ;Multiply by 2
ADD AL,AH ;Add the carry
AAM ;Adjust for dec multiplication
MOV [DI],AL ;Put the byte back
INC DI ;Point to next byte
LOOP DECDOUBLE1
RET
DECDOUBLE ENDP
;-----------------------------------------------------------------------------
;Halve a temporary decimal floating point number
DECHALF PROC NEAR
;
;First shift up one digit
MOV CX,25 ;For a count of 25
MOV AL,0 ;Zero previous digit
DECHALF1:
XCHG AL,[DI] ;Exchange with current digit
INC DI ;Point to next digit
LOOP DECHALF1
DEC DECEXP ;Decrement decimal digit
;
;Now divide by 2
MOV CX,25 ;For a count of 25
MOV AH,0 ;Clear carry
DECHALF2:
PUSH CX ;Save count
DEC DI ;Point to next digit
MOV AL,[DI] ;Get the digit
MOV CL,2 ;Divisor of 2
AAD ;Adjust for decimal division
DIV CL ;Divide
MOV [DI],AL ;Put it back
POP CX ;Restore count
LOOP DECHALF2
RET
DECHALF ENDP
;-----------------------------------------------------------------------------
;Normalize a temporary decimal floating point number
DECNORM PROC NEAR
;
;Check top + 1 digit
CMP DIBYTE+22,0 ;Is it already zero ?
JE DECNORM_XIT ;If so, go
;
;Round up, starting with bottom digit
MOV AL,[DI] ;First digit
ADD AL,AL ;Double it for rounding
MOV AH,0 ;Prepare carry
AAA ;Adjust for decimal
;
;Now shift the rest
MOV CX,24 ;For a count of 24
DECNORM1:
MOV AL,[DI+1] ;Get next digit
ADD AL,AH ;Add carry
MOV AH,0 ;Prepare next carry
AAA ;Adjust for decimal
MOV [DI],AL ;Put digit in place
INC DI ;Point to next digit
LOOP DECNORM1
INC DECEXP ;Increment decimal exponent
DECNORM_XIT:
RET
DECNORM ENDP
;-----------------------------------------------------------------------------
;Convert from double to single precision floating point
DFP2SFP PROC FAR
PUSH AX ;Save register
MOV AX,DFPBUFFW4 ;Get word from double precision
MOV SFPBUFFW0,AX ;Put it in single precision
MOV AX,DFPBUFFW6 ;Get word from double precision
MOV SFPBUFFW2,AX ;Put it in single precision
PUSH AX ;Restore register
RET
DFP2SFP ENDP
;-----------------------------------------------------------------------------
;Convert from internal floating point to internal 16-bit integer (truncate)
FIX PROC FAR
;
;The number is in SFPBUFF
PUSH CX ;Save registers
PUSH AX
;
;Get the mantissa
MOV AX,SFPBUFFW0 ;AX gets low part
MOV AX,SFPBUFFW2 ;DX gets high part
AND DX,007FH ;Just the mantissa
OR DX,0080H ;Restore the MSB
;
;Get the exponent
MOV CL,SFPBUFFB3
MOV CH,0 ;Extend to 16-bit
SUB CX,88H ;Subtract bias +
CMP CX,0 ;Check its sign
JL FIX1 ; if negative
JG FIX3 ; if positive
JE FIX4 ; if zero
;
;Shift right
FIX1:
NEG CX ;Absolute value
FIX2:
SAR DX,1 ;Shift all bits right
RCR AX,1 ;Carry on
LOOP FIX2
JMP FIX4 ;End of case negative
;
;Shift left
FIX3:
SAL AX,1 ;Shift all bits left
RCL DX,1 ;Carry on
LOOP FIX3
JMP FIX4 ;End of case positive
;
;Check the sign
FIX4:
MOV AL,SFPBUFFB2 ;Get sign
AND AL,80H ;Just bit 7
JZ FIX_XIT ;Is it on ?
NEG DX ;Two's complement if negative
;
FIX_XIT:
POP AX ;Restore registers
POP CX
RET
FIX ENDP
;-----------------------------------------------------------------------------
;Convert from 16-bit integer to floating point
FLOAT PROC FAR
;
;The number is in DX
PUSH DX ;Save registers
PUSH CX
PUSH AX
MOV AX,0 ;Extend to 32 bits
CMP DX,0 ;Check if zero
JZ FLOAT4
FLOAT1:
MOV CX,9800H ;Initialize exponent & sign
;
;Shift left until normalized
FLOAT2:
TEST AX,0080H ;Done yet ?
JNZ FLOAT3 ;If so, go
SAL DX,1 ;If not, shift all bits left
RCL AX,1 ;Carry on
DEC CH ;Decrement the exponent
JMP FLOAT2
;
;Pack it in
FLOAT3:
AND AX,007FH ;Just the mantissa
OR